﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools;

namespace BasecampSync
{
    /// <summary>
    /// 
    /// </summary>
    class TaskSync
    {        
        private Outlook.MAPIFolder myFolder;
        private BasecampApi api;

        /// <summary>
        /// Constructor, loads api and Outlook connection
        /// </summary>
        /// <param name="outlookObj"></param>
        public TaskSync(Outlook._Application outlookObj, BasecampApi api)
        {
            this.api = api;
            this.myFolder = (Outlook.MAPIFolder)outlookObj.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderTasks);
        }

        /// <summary>
        /// Syncs Basecamp and Outlook tasks
        /// </summary>
        public void Sync(List<Project> projects)
        {
            foreach (Project curProject in projects)
            {
                List<TodoList> basecampLists = api.GetTodoLists(curProject.Id);

                // Itteriere Basecamp Tasks und Update Basecamp
                foreach (TodoList curBasecampList in basecampLists)
                {
                    Outlook.MAPIFolder folder = FolderExists(curBasecampList.Name);

                    if (folder == null)
                    {
                        InsertList(curBasecampList);
                    }
                    else
                    {
                        CompareBasecampOutlook(curBasecampList, folder);
                    }
                }
            }
        }

        /// <summary>
        /// (Depreciated) Imports a basecamp todo list as Outlook tasks in a new Outlook folder
        /// </summary>
        /// <example>
        /// <code>
        /// BasecampApi api = new BasecampApi("nocarrier", "idkfa14");
        /// List<Project> testing = test.GetProjectList();
        /// List<TodoList> lists = test.GetTodoLists(testing[0].Id);
        /// </code>
        /// </example>
        /// <param name="lists"></param>
        private void ImportItems(List<TodoList> lists)
        {
            foreach (TodoList curList in lists)
            {
                if (curList.TodoItems == null || curList.TodoItems.Count == 0)
                    continue;

                foreach (TodoItem curItem in curList.TodoItems)
                {
                    // Insert Item in Outlook
                    Outlook.TaskItem taskItem = (Outlook.TaskItem)this.myFolder.Items.Add(Outlook.OlItemType.olTaskItem);

                    if (curItem.Content.Length > 10)
                    {
                        taskItem.Subject = curItem.Content.Substring(0, 10) + "...";
                    }
                    else
                    {
                        taskItem.Subject = curItem.Content;
                    }

                    taskItem.Body = curItem.Content;

                    if (curItem.Completed)
                    {
                        taskItem.Status = Microsoft.Office.Interop.Outlook.OlTaskStatus.olTaskComplete;
                    }
                    else
                    {
                        taskItem.Status = Microsoft.Office.Interop.Outlook.OlTaskStatus.olTaskNotStarted;
                    }

                    //taskItem.CreationTime = curItem.Created;
                    taskItem.UserProperties.Add("basecamp-id", Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText, false, null);
                    //taskItem.UserProperties.Find("item-id", true) && taskItem.UserProperties["basecamp-id"];
                    taskItem.Save();
                }
            }
        }

        /// <summary>
        /// Compares existing Basecamp and 
        /// </summary>
        /// <param name="basecampList"></param>
        /// <param name="folder"></param>
        private void CompareBasecampOutlook(TodoList basecampList, Outlook.MAPIFolder folder)
        {
            // List<TodoItem> exportToBasecamp = new List<TodoItem>();

            // Synchronize items that exist on both sides
            foreach (TodoItem basecampItem in basecampList.TodoItems)
            {
                foreach (Outlook.TaskItem outlookItem in folder.Items)
                {
                    if (outlookItem.UserProperties.Find("basecamp-id", true) == null || String.IsNullOrEmpty(outlookItem.UserProperties["basecamp-id"].Value.ToString()))
                    {
                        // Item ex. noch nicht in basecamp
                        api.InsertTodoItem(basecampList.Id, outlookItem.Body);
                    }
                    else if(outlookItem.UserProperties["basecamp-id"].Value.ToString() == basecampItem.Id.ToString())
                    {
                        // Item ex. in Basecamp und Outlook
                        if (basecampItem.Completed == outlookItem.Complete)
                        {
                            // Nothing to do here
                            continue;
                        }
                        else
                        {
                            if (outlookItem.Complete && !basecampItem.Completed)
                            {
                                api.MarkTodoAsComplete(basecampItem.Id);
                            }
                            else if (!outlookItem.Complete && basecampItem.Completed)
                            {
                                outlookItem.Complete = true;
                                outlookItem.Save();
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Imports a Basecamp list into a new Outlook folder
        /// </summary>
        /// <param name="newList"></param>
        private void InsertList(TodoList newList)
        {
            // Create folder
            Outlook.MAPIFolder listFolder =
                this.myFolder.Folders.Add(newList.Name, Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderTasks);

            // Insert every Basecamp item and insert it in Outlook
            foreach (TodoItem curItem in newList.TodoItems)
            {
                Outlook.TaskItem taskItem = (Outlook.TaskItem)listFolder.Items.Add(Outlook.OlItemType.olTaskItem);

                // Set subject
                if (curItem.Content.Length > 15)
                {
                    taskItem.Subject = curItem.Content.Substring(0, 13) + "...";
                }
                else
                {
                    taskItem.Subject = curItem.Content;
                }

                // Body
                taskItem.Body = curItem.Content;

                // Set complete status
                if (curItem.Completed)
                {
                    taskItem.Status = Microsoft.Office.Interop.Outlook.OlTaskStatus.olTaskComplete;
                }
                else
                {
                    taskItem.Status = Microsoft.Office.Interop.Outlook.OlTaskStatus.olTaskNotStarted;
                }

                // Set user properties
                //taskItem.CreationTime = curItem.Created;
                taskItem.UserProperties.Add("basecamp-id", Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText, false, null);
                taskItem.UserProperties["basecamp-id"].Value = curItem.Id.ToString();
                //taskItem.UserProperties.Find("item-id", true) && taskItem.UserProperties["basecamp-id"];


                taskItem.Save();
            }
        }

        /// <summary>
        /// Searches a custom folder
        /// </summary>
        /// <param name="needle"></param>
        /// <returns>Reference to the searched folder, null if it does not exists</returns>
        public Outlook.MAPIFolder FolderExists(string needle)
        {
            foreach (Outlook.MAPIFolder subFolder in this.myFolder.Folders)
            {
                if (subFolder.Name == needle)
                {
                    return subFolder;
                }
            }

            return null;
        }

        /// <summary>
        /// Searches a todo list with the given <c>id</c>
        /// </summary>
        /// <param name="haystack"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        private TodoItem Search(List<TodoList> haystack, UInt32 id)
        {
            foreach (TodoList curList in haystack)
            {
                foreach (TodoItem curItem in curList.TodoItems)
                {
                    if (curList.Id == id)
                    {
                        return curItem;
                    }
                }
            }

            return new TodoItem();
        }
    }
}
